x86: fix map_domain_page() last resort fallback
authorJan Beulich <jbeulich@suse.com>
Thu, 13 Jun 2013 08:49:01 +0000 (10:49 +0200)
committerJan Beulich <jbeulich@suse.com>
Thu, 13 Jun 2013 08:49:01 +0000 (10:49 +0200)
Guests with vCPU count not divisible by 4 have unused bits in the last
word of their inuse bitmap, and the garbage collection code therefore
would get mislead believing that some entries were actually recoverable
for use.

Also use an earlier established local variable in mapcache_vcpu_init()
instead of re-calculating the value (noticed while investigating the
generally better option of setting those overhanging bits once during
setup - this didn't work out in a simple enough fashion because the
mapping getting established there isn't in the current address space,
and hence the bitmap isn't directly accessible there).

Reported-by: Konrad Wilk <konrad.wilk@oracle.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Keir Fraser <keir@xen.org>
xen/arch/x86/domain_page.c

index efda6afd8bbeddc3d42b9fc3bbea50142e003aba..9297ea07e672149fea129e37e8e46295c8516422 100644 (file)
@@ -110,16 +110,17 @@ void *map_domain_page(unsigned long mfn)
     idx = find_next_zero_bit(dcache->inuse, dcache->entries, dcache->cursor);
     if ( unlikely(idx >= dcache->entries) )
     {
-        unsigned long accum = 0;
+        unsigned long accum = 0, prev = 0;
 
         /* /First/, clean the garbage map and update the inuse list. */
         for ( i = 0; i < BITS_TO_LONGS(dcache->entries); i++ )
         {
+            accum |= prev;
             dcache->inuse[i] &= ~xchg(&dcache->garbage[i], 0);
-            accum |= ~dcache->inuse[i];
+            prev = ~dcache->inuse[i];
         }
 
-        if ( accum )
+        if ( accum | (prev & BITMAP_LAST_WORD_MASK(dcache->entries)) )
             idx = find_first_zero_bit(dcache->inuse, dcache->entries);
         else
         {
@@ -279,8 +280,7 @@ int mapcache_vcpu_init(struct vcpu *v)
     if ( ents > dcache->entries )
     {
         /* Populate page tables. */
-        int rc = create_perdomain_mapping(d, MAPCACHE_VIRT_START,
-                                          d->max_vcpus * MAPCACHE_VCPU_ENTRIES,
+        int rc = create_perdomain_mapping(d, MAPCACHE_VIRT_START, ents,
                                           NIL(l1_pgentry_t *), NULL);
 
         /* Populate bit maps. */